home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_075 / eless / eless.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  8KB  |  308 lines

  1. /* :ts=8 bk=0
  2.  * 
  3.  * eless.c:    An attempt at a reasonable-speed 'ls' program by fiddling
  4.  *        with the DOS.
  5.  *
  6.  *        Compiles under Manx 3.20 and patched 3.40.
  7.  *        cc eless.c
  8.  *        ln eless.c -lc -o eless
  9.  *
  10.  * Leo L. Schwab        8704.26        (415)-456-6565
  11.  */
  12.  
  13. #include <exec/types.h>
  14. #include <exec/memory.h>
  15. #include <libraries/dosextens.h>
  16.  
  17. #define    BLOCKSIZE    128
  18. #define    STARTTAB    6
  19. #define ENDTAB        (BLOCKSIZE-51)
  20. #define    TABSIZ        (BLOCKSIZE-56)
  21. #define    FILENAME    (BLOCKSIZE-20)
  22. #define    HASHCHAIN    (BLOCKSIZE-4)
  23. #define    SECONDARY    (BLOCKSIZE-1)
  24. #define    ST_DIR        2
  25. #define    ST_FILE        -3
  26.  
  27. /*
  28.  * Note:  I usually declare Amiga functions this way to disable the compiler's
  29.  * type checking.  This allows me to assign values to variables without
  30.  * explicitly casting them to the appropriate type.  In reality, these
  31.  * functions return things entirely different from the way I've declared
  32.  * them.  For example, CreatePort() should really be declared as:
  33.  *
  34.  * struct MsgPort *CreatePort();
  35.  *
  36.  * Caveat Programmer.
  37.  */
  38. extern void    *AllocMem(), *CreatePort(), *RemTail(), *FindTask();
  39. extern long    Lock(), Examine();
  40.  
  41. long        dopacket();
  42. int        longcmp(), namecmp();
  43.  
  44.  
  45. struct StandardPacket    *packet;
  46. struct FileInfoBlock    *fib;
  47. struct FileLock        *lock;
  48. struct InfoData        *id;
  49. struct MsgPort        *dosreply;
  50. BPTR            lok;
  51. long            *buf, hashtab[TABSIZ];
  52.  
  53.  
  54. main (ac, av)
  55. char **av;
  56. {
  57.     int flag;
  58.  
  59.     openstuff ();
  60.  
  61.     if (ac < 2)        /*  No arguments; do current directory  */
  62.         printdir (((struct Process *) FindTask (0L)) -> pr_CurrentDir);
  63.  
  64.     else {            /*  Arguments; treat as directories  */
  65.         flag = (ac > 2);
  66.         while (++av, --ac) {
  67.             if (!(lok = Lock (*av, ACCESS_READ))) {
  68.                 printf ("%s: Not found.\n", *av);
  69.                 if (ac > 1)
  70.                     putchar ('\n');
  71.                 continue;
  72.             }
  73.  
  74.             if (!Examine (lok, fib))
  75.                 die ("Examine failed.");
  76.             if (fib -> fib_DirEntryType < 0) {
  77.                 printf ("%s: Not a directory.\n", *av);
  78.                 if (ac > 1)
  79.                     putchar ('\n');
  80.                 continue;
  81.             }
  82.  
  83.             if (flag)
  84.                 printf ("%s:\n", *av);
  85.             printdir (lok);
  86.             if (ac > 1)
  87.                 putchar ('\n');
  88.             UnLock (lok);  lok = NULL;
  89.         }
  90.     }
  91.  
  92.     closestuff ();
  93. }
  94.  
  95.  
  96. /*
  97.  * This function prints the directory in a nice, pretty columnar format.
  98.  */
  99. printdir (dirlock)
  100. BPTR dirlock;
  101. {
  102.     struct List        namelist;
  103.     register struct Node    *name, **namearray;
  104.     long            args[2];
  105.     register int        i, n;
  106.     int            len = 0, ncols, nlines, nfiles = 0;
  107.     char            fmt1[16], fmt2[16];
  108.     char            *fn = (char *) (&buf[FILENAME]) + 1;
  109.  
  110.     lock = (struct FileLock *) (dirlock << 2);
  111.     args[0] = lock -> fl_Key;    /*  Block number  */
  112.     args[1] = (long) buf >> 2;    /*  BPTR to buffer  */
  113.  
  114.     /*  Attempt to get raw directory block.  */
  115.     if (!dopacket (lock -> fl_Task, ACTION_GET_BLOCK, args, 2)) {
  116.         if (packet -> sp_Pkt.dp_Res2 == ERROR_ACTION_NOT_KNOWN)
  117.             printf ("Not a block device.\n");
  118.         else
  119.             printf ("Error %ld while getting dirblock.\n",
  120.                 packet -> sp_Pkt.dp_Res2);
  121.         return;
  122.     }
  123.  
  124.     /*  Copy DOS's hash table into our array.  */
  125.     for (i=0; i<TABSIZ; i++)
  126.         hashtab[i] = buf[i+STARTTAB];
  127.  
  128.     NewList (&namelist);
  129.     while (1) {
  130.         /*  Sort hash table.  */
  131.         qsort (hashtab, TABSIZ, sizeof (long), longcmp);
  132.         if (!hashtab[0])    /*  Empty hash table  */
  133.             break;
  134.  
  135.         /*
  136.          * Retrieve disk blocks according to sorted hash table and
  137.          * collect filenames.
  138.          */
  139.         for (i=0; hashtab[i] && i<TABSIZ; i++) {
  140.             args[0] = hashtab[i];
  141.             dopacket (lock -> fl_Task, ACTION_GET_BLOCK, args, 2);
  142.  
  143.             if (!(name = AllocMem (sizeof (*name) + *(fn-1) + 1L,
  144.                            MEMF_CLEAR))) {
  145.                 puts ("Node memory allocation failure.");
  146.                 goto bombout;
  147.             }
  148.  
  149.             name -> ln_Name = (char *) name + sizeof (*name);
  150.             name -> ln_Type = (buf[SECONDARY] == ST_DIR);
  151.             fn[*(fn-1)] = '\0';    /*  Force null-termination  */
  152.             strcpy (name -> ln_Name, fn);
  153.             AddTail (&namelist, name);
  154.             nfiles++;    /*  Number of files found  */
  155.  
  156.             hashtab[i] = buf[HASHCHAIN];
  157.         }
  158.     }
  159.     if (!nfiles)    /*  No files  */
  160.         return;
  161.  
  162.     /*  Create array that qsort can deal with.  */
  163.     if (!(namearray = AllocMem
  164.                ((long) nfiles * sizeof (char *), MEMF_CLEAR))) {
  165.         puts ("Name array allocation failure.");
  166.         goto bombout;
  167.     }
  168.  
  169.     /*  Load up the array.  */
  170.     for (name = namelist.lh_Head, i=0;
  171.          name -> ln_Succ;
  172.          name = name -> ln_Succ, i++)
  173.              namearray[i] = name;
  174.  
  175.     /*  Alphabetize filenames.  */
  176.     qsort (namearray, nfiles, sizeof (struct Node *), namecmp);
  177.  
  178.     /*  Find longest string so we can format intelligently.  */
  179.     for (i=0; i<nfiles; i++)
  180.         if ((n = strlen (namearray[i] -> ln_Name)) > len)
  181.             len = n;
  182.     len += 2;    /*  Inter-name spacing  */
  183.  
  184.     /*  Print them suckers out  */
  185.     ncols = 77 / len;        /*  Assume CON: is 77 columns  */
  186.     nlines = nfiles/ncols + (nfiles%ncols != 0);
  187.     sprintf (fmt1, "%%-%ds", len);        /*  Normal format string  */
  188.     sprintf (fmt2, "\033[33m%%-%ds\033[m", len);    /* For directories */
  189.     for (i=0; i<nlines; i++) {
  190.         for (n=i; n<nfiles; n+=nlines)
  191.             printf (namearray[n] -> ln_Type ? fmt2 : fmt1,
  192.                 namearray[n] -> ln_Name);
  193.         putchar ('\n');
  194.     }
  195.  
  196.     /*  Phew!  Now free all the stuff we allocated.  */
  197. bombout:
  198.     freenamelist (&namelist);
  199.     if (namearray)
  200.         FreeMem (namearray, (long) nfiles * sizeof (struct Node *));
  201. }
  202.  
  203. freenamelist (list)
  204. struct List *list;
  205. {
  206.     register struct Node *now;
  207.  
  208.     while (now = RemTail (list))
  209.         FreeMem (now, sizeof (*now) + strlen (now -> ln_Name) + 1L);
  210. }
  211.  
  212.  
  213. /*
  214.  * This function assumes the existence of a properly initialized
  215.  * standardpacket structure called "packet" and a reply port called
  216.  * "dosreply".  A more general function would not do this.
  217.  *
  218.  * This function is synchronous i.e. it doesn't return until the specified
  219.  * action has been performed.
  220.  */
  221. long
  222. dopacket (proc, action, args, nargs)
  223. struct MsgPort *proc;
  224. long action;
  225. register long *args;
  226. register int nargs;
  227. {
  228.     register long *argp = &packet -> sp_Pkt.dp_Arg1;
  229.  
  230.     for (; nargs>0; nargs--)
  231.         *argp++ = *args++;
  232.  
  233.     /*
  234.      * AmigaDOS scribbles over the reply port, so we have to initialize
  235.      * it every time we send a packet.
  236.      */
  237.     packet -> sp_Pkt.dp_Port = dosreply;
  238.     packet -> sp_Pkt.dp_Type = action;
  239.  
  240.     PutMsg (proc, packet);
  241.     WaitPort (dosreply);
  242.     GetMsg (dosreply);
  243.  
  244.     return (packet -> sp_Pkt.dp_Res1);
  245. }
  246.  
  247.  
  248. /*
  249.  * These functions are called by qsort().  The sense of camparisons is
  250.  * reversed in longcmp to get a reverse sort (largest elements first).
  251.  */
  252. longcmp (foo, bar)
  253. long *foo, *bar;
  254. {
  255.     /*
  256.      * We have to do it this way because qsort() expects an int to be
  257.      * returned.  Subtracting longs directly might overflow a 16-bit int.
  258.      */
  259.     return ((*foo < *bar) - (*foo > *bar));
  260. }
  261.  
  262. namecmp (foo, bar)
  263. struct Node **foo, **bar;
  264. {
  265.     return (strcmp ((*foo) -> ln_Name, (*bar) -> ln_Name));
  266. }
  267.  
  268.  
  269. /*
  270.  * Resource allocation/deallocation routines.
  271.  */
  272. openstuff ()
  273. {
  274.     if (!(packet = AllocMem ((long) sizeof (*packet), MEMF_CLEAR)))
  275.         die ("Can't allocate packet space.");
  276.  
  277.     if (!(dosreply = CreatePort (NULL, NULL)))
  278.         die ("Dos reply port create failed.");
  279.     packet -> sp_Msg.mn_Node.ln_Name    = (char *) &packet -> sp_Pkt;
  280.     packet -> sp_Pkt.dp_Link        = &packet -> sp_Msg;
  281.  
  282.     if (!(fib = AllocMem ((long) sizeof (*fib), MEMF_CLEAR)))
  283.         die ("Can't allocate FileInfoBlock.");
  284.  
  285.     /*
  286.      * Note:  This allocation may not work with DMA hard disks.
  287.      */
  288.     if (!(buf = AllocMem (BLOCKSIZE * 4L, MEMF_CHIP | MEMF_PUBLIC)))
  289.         die ("Couldn't allocate sector buffer.");
  290. }
  291.  
  292. closestuff ()
  293. {
  294.     if (lok)        UnLock (lok);
  295.     if (buf)        FreeMem (buf, BLOCKSIZE * 4L);
  296.     if (fib)        FreeMem (fib, (long) sizeof (*fib));
  297.     if (dosreply)        DeletePort (dosreply);
  298.     if (packet)        FreeMem (packet, (long) sizeof (*packet));
  299. }
  300.  
  301. die (str)
  302. char *str;
  303. {
  304.     puts (str);
  305.     closestuff ();
  306.     exit (1);
  307. }
  308.